import ctypes
from ctypes import *
import time
import sys
import os


class SerialPort:
    def __init__(self):
        # 根据操作系统加载正确的库
        try:
            if sys.platform.startswith('win'):
                self.lib = ctypes.CDLL('./c/serial_c.dll')
            else:
                self.lib = ctypes.CDLL('./serial.so')
        except Exception as e:
            raise Exception(f"加载动态库失败: {e}")

        # 定义函数参数类型
        self.lib.openSerial.argtypes = [c_char_p, c_int]
        self.lib.openSerial.restype = c_int

        self.lib.closeSerial.argtypes = [c_int]
        self.lib.closeSerial.restype = None

        self.lib.sendData.argtypes = [c_int, POINTER(c_ubyte), c_int]
        self.lib.sendData.restype = c_int

        self.lib.receiveData.argtypes = [c_int, POINTER(c_ubyte), c_int]
        self.lib.receiveData.restype = c_int

        self.handle = -1

    def format_port_name(self, port_name):
        """格式化串口名称"""
        if sys.platform.startswith('win'):
            # Windows系统下添加'\\.\'前缀
            if not port_name.startswith('\\\\.\\'):
                port_name = '\\\\.\\' + port_name
        return port_name

    def open(self, port_name, baud_rate):
        """打开串口"""
        try:
            formatted_port = self.format_port_name(port_name)
            self.handle = self.lib.openSerial(formatted_port.encode(), baud_rate)

            if self.handle < 0:
                if sys.platform.startswith('win'):
                    error_code = ctypes.get_last_error()
                else:
                    print(f"打开串口失败，请检查权限和设备名称")
                return False

            return True

        except Exception as e:
            print(f"打开串口时发生异常: {e}")
            return False

    def close(self):
        """关闭串口"""
        if self.handle >= 0:
            try:
                self.lib.closeSerial(self.handle)
                self.handle = -1
            except Exception as e:
                print(f"关闭串口时发生异常: {e}")

    def send(self, data):
        """发送数据"""
        if self.handle < 0:
            print("串口未打开")
            return -1

        try:
            if isinstance(data, str):
                data = data.encode()
            buffer = (c_ubyte * len(data))(*data)
            result = self.lib.sendData(self.handle, buffer, len(data))
            return result
        except Exception as e:
            print(f"发送数据时发生异常: {e}")
            return -1

    def receive(self, buffer_size=1024):
        """接收数据"""
        if self.handle < 0:
            print("串口未打开")
            return b''

        try:
            buffer = (c_ubyte * buffer_size)()
            bytes_read = self.lib.receiveData(self.handle, buffer, buffer_size)
            if bytes_read > 0:
                return bytes(buffer[:bytes_read])
            return b''
        except Exception as e:
            print(f"接收数据时发生异常: {e}")
            return b''


# 使用示例
if __name__ == '__main__':
    # 创建串口对象
    serial = SerialPort()

    # 获取要打开的串口号
    if sys.platform.startswith('win'):
        port = input("请输入串口号(例如 COM1): ")
    else:
        port = input("请输入串口设备(例如 /dev/ttyUSB0): ")

    # 打开串口
    if serial.open(port, 9600):
        try:
            # 发送测试数据
            print("发送测试数据...")
            serial.send("Hello World")

            # 等待接收数据
            print("等待接收数据...")
            data = serial.receive()
            if data:
                print(f"收到数据: {data}")
            else:
                print("未收到数据")

        finally:
            # 确保关闭串口
            serial.close()
    else:
        print("串口打开失败，请检查:")
        print("1. 串口名称是否正确")
        print("2. 串口是否被其他程序占用")
        print("3. 是否有足够的权限")
        if not sys.platform.startswith('win'):
            print("4. Linux系统请确保用户在dialout组中")

